package com.nus.fellowmark.modules.assignment.service.impl;

import com.nus.fellowmark.dao.GradeDao;
import com.nus.fellowmark.entity.GradeEntity;
import com.nus.fellowmark.entity.PairingEntity;
import com.nus.fellowmark.entity.RubricEntity;
import com.nus.fellowmark.modules.assignment.dto.GradeDTO;
import com.nus.fellowmark.modules.assignment.service.GradeService;
import com.nus.fellowmark.modules.assignment.service.PairingService;
import com.nus.fellowmark.modules.assignment.service.RubricService;
import com.nus.fellowmark.modules.assignment.vo.GradeAsgVO;
import com.nus.fellowmark.modules.assignment.vo.GradeStuVO;
import com.nus.fellowmark.modules.assignment.vo.GradeVO;
import com.nus.fellowmark.modules.assignment.vo.PairingVO;
import com.nus.fellowmark.modules.user.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nus.fellowmark.common.utils.PageUtils;
import com.nus.fellowmark.common.utils.Query;


@Service("gradeService")
public class GradeServiceImpl extends ServiceImpl<GradeDao, GradeEntity> implements GradeService {
    @Autowired
    private RubricService rubricService;

    @Autowired
    private GradeDao gradeDao;

    @Autowired
    private PairingService pairingService;

    @Autowired
    private UserService userService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<GradeEntity> page = this.page(
                new Query<GradeEntity>().getPage(params),
                new QueryWrapper<GradeEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public Boolean gradeAssignment(GradeDTO gradeDTO) {
        GradeEntity gradeEntity = new GradeEntity();
        BeanUtils.copyProperties(gradeDTO, gradeEntity);
        RubricEntity rubric = rubricService.getOne(new QueryWrapper<RubricEntity>().eq("question_id", gradeDTO.getQuestionId()));
        if (rubric == null) {
            return Boolean.FALSE;
        }
        Integer grade = gradeDTO.getGrade();
        if (rubric.getMaxMark() < grade || rubric.getMinMark() > grade) {
            return Boolean.FALSE;
        }
        gradeEntity.setRubricId(rubric.getId());
        return this.save(gradeEntity);
    }

    @Override
    public GradeVO listGradeByPairIdAndRubricId(Integer pairId, Integer rubricId) {
        GradeEntity gradeEntity = gradeDao.selectByPairIdAndRubricId(pairId, rubricId);
        PairingEntity pairingEntity = pairingService.getStudentIdByPairId(pairId);
        if (gradeEntity == null || pairingEntity == null) {
            return null;
        }

        GradeVO gradeVO = new GradeVO();
        gradeVO.setGradeId(gradeEntity.getId());
        gradeVO.setPairingId(pairId);
        gradeVO.setStudentId(pairingEntity.getStudentId());
        gradeVO.setMarkerId(pairingEntity.getMarkerId());
        gradeVO.setSubmissionId(gradeEntity.getSubmissionId());
        gradeVO.setRubricId(gradeEntity.getRubricId());
        gradeVO.setGrade(gradeEntity.getGrade());
        gradeVO.setComment(gradeEntity.getComment());
        return gradeVO;
    }

    @Override
    public List<GradeEntity> listGradeByPairId(Integer pairId) {
        List<GradeEntity> gradeEntities = gradeDao.selectByPairId(pairId);
        PairingEntity pairingEntity = pairingService.getStudentIdByPairId(pairId);
        if (gradeEntities == null || pairingEntity == null) {
            return null;
        }
        gradeEntities.sort(Comparator.comparing(GradeEntity::getRubricId));
        return gradeEntities;
    }

    @Override
    public List<GradeAsgVO> listGradeByAssignmentId(Integer assignmentId) {
        List<PairingVO> pairingVOS = pairingService.listPairsOfAssignment(assignmentId);
        List<GradeAsgVO> gradeAsgVOS = new ArrayList<>();
        for (int i = 0; i < pairingVOS.size(); i++) {
            PairingVO pairingVO = pairingVOS.get(i);
            if (pairingVO == null) {
                continue;
            }
            List<GradeEntity> gradeEntities = gradeDao.selectByPairId(pairingVO.getId());
            gradeEntities.sort(Comparator.comparing(GradeEntity::getRubricId));
            for (GradeEntity gradeEntity : gradeEntities) {
                GradeAsgVO gradeAsgVO = new GradeAsgVO();
                gradeAsgVO.setPairingId(pairingVO.getId());
                gradeAsgVO.setSubmissionId(gradeEntity.getSubmissionId());
                gradeAsgVO.setGrade(gradeEntity.getGrade());
                gradeAsgVO.setRubricId(gradeEntity.getRubricId());
                gradeAsgVO.setStudentId(pairingVO.getStudentId());
                gradeAsgVO.setMarkerId(pairingVO.getMarkerId());
                gradeAsgVO.setStudentName(userService.getUserName(pairingVO.getStudentId()));
                gradeAsgVO.setMarkerName(userService.getUserName(pairingVO.getMarkerId()));
                gradeAsgVOS.add(gradeAsgVO);
            }
        }
        return gradeAsgVOS;
    }

    @Override
    public List<GradeStuVO> listGradeByStuId(Integer stuId, Integer assignmentId) {
       List<PairingEntity> pairs = pairingService.listPairsByStuAndAsgId(stuId, assignmentId);

       List<GradeStuVO> gradeStuVOS = new ArrayList<>();
       for (PairingEntity pair : pairs) {
           List<GradeEntity> gradeEntities = gradeDao.selectByPairId(pair.getId());
           gradeEntities.sort(Comparator.comparing(GradeEntity::getRubricId));
           for (GradeEntity gradeEntity : gradeEntities) {
                if (gradeEntity == null) {
                    continue;
                }
                GradeStuVO gradeStuVO = new GradeStuVO();
                gradeStuVO.setPairingId(pair.getId());
                gradeStuVO.setGrade(gradeEntity.getGrade());
                gradeStuVO.setRubricId(gradeEntity.getRubricId());
                gradeStuVO.setMarkerId(pair.getMarkerId());
                gradeStuVOS.add(gradeStuVO);
            }
       }
       return gradeStuVOS;
    }

}
